
圖片來源:https://artprojectsforkids.org/how-to-draw-a-dolphin/
請注意,透過 Flipper Zero 學習的資訊技術與知識,目的在於提升個人的技術能力和資安意識。我們強烈呼籲大家,絕對不要使用所學知識從事任何違法行為。您的合法使用是我們的期望,也是您自身責任的
一部分。
我們要繼續提到 SceneManager 透過一系列的 scene_manager_* 開頭的函式來管理應用程式中的所有場景細節。主要是確保當進入場景、離開場景或接收到新事件時,相關的處理函式會被正確的呼叫。
另一個是 ViewDispatcher 是使用許多 view_dispatcher_* 的函式來管理 views。這些函式會在 SceneManager 中被呼叫。總之,ViewDispatcher 是負責處理場景中 Views 的顯示和管理。
當我們在定義應用程式場景時,應提供所有場景處理函式作為一個 SceneManagerHandlers 結構傳給 scene_manager_alloc 函式。例如說作者這邊的場景會用數字做為索引,同時為了方便追蹤這些場景,通常我們會定義一個 enum 類型來表示場景的索引,像是:
typedef enum {
    TestAppScene_MainMenu,      // 主選單場景
    TestAppScene_FirstPopup,    // 第一個彈出視窗場景
    TestAppScene_SecondPopup,   // 第二個彈出視窗場景
    TestAppScene_count          // 場景計數,方便後續擴展
} TestAppScene;
像是這邊的 count 只要放在枚舉的最後一項,之後增加或是修改場景數量的時候都可以輕鬆算出場景的總數。
而視圖是可以重複使用的,因此應用程式中可能場景數量會比視圖更多。換句話說,我們有可能一個視圖對應多個場景:
typedef enum {
    TestAppView_Menu,   // 菜單視圖
    TestAppView_Popup   // 彈出視圖
} TestAppScene;
這樣也提高了資源利用率。
首先我們會在 test_app_init 函式裡面初始化 scene manager 以及 view dispatcher:
TestApp* app = malloc(sizeof(TestApp));
test_app_scene_manager_init(app);
test_app_view_dispatcher_init(app);
app->scene_manager = scene_manager_alloc(&test_app_scene_event_handlers, app);
我們為 SceneManager 分配記憶體。
其中這邊的第二個參數是 context,當場景處理方法被調用時,會回傳這個 context,第一個參數是 SceneManagerHandlers* test_app_scene_event_handlers 已經提前定義好並包含 on_enter、on_exit、on_event 處理函式集合。
on_enter_handlers:當進入某個場景時會調用這個處理函式集合,它包含了所有場景的進入處理邏輯。這些函式與定義的 enum 順序一致。例如,進入主選單或彈出視窗時會調用對應的進入函數。
void (*const test_app_scene_on_enter_handlers[])(void*) = {
    test_app_scene_on_enter_main_menu,
    test_app_scene_on_enter_popup_one,
    test_app_scene_on_enter_popup_two};
on_event_handlers:當某個場景處於活動狀態時,並且收到了事件(如使用者操作),會調用這個事件處理函式集合。每個場景有其專屬的事件處理邏輯,也是與 enum 順序一致。
bool (*const test_app_scene_on_event_handlers[])(void*, SceneManagerEvent) = {
    test_app_scene_on_event_main_menu,
    test_app_scene_on_event_popup_one,
    test_app_scene_on_event_popup_two};
on_exit_handlers:當離開某個場景時,會調用這個處理函式集合。這些函式負責處理場景退出時的清理或其他工作,同樣是與 enum 順序保持一致。
void (*const test_app_scene_on_exit_handlers[])(void*) = {
    test_app_scene_on_exit_main_menu,
    test_app_scene_on_exit_popup_one,
    test_app_scene_on_exit_popup_two};
test_app_scene_event_handlers:這是所有場景處理器的集合,包含 on_enter、on_event 和 on_exit 的處理函數。這樣的結構可以確保每個場景的進入、事件處理和退出邏輯都能正確運行。
const SceneManagerHandlers test_app_scene_event_handlers = {
    .on_enter_handlers = test_app_scene_on_enter_handlers,   // 進入處理函式集合
    .on_event_handlers = test_app_scene_on_event_handlers,   // 事件處理函式集合
    .on_exit_handlers = test_app_scene_on_exit_handlers,     // 退出處理函式集合
    .scene_num = TestAppScene_count};                       // 場景數量
test_app_view_dispatcher_init 函式負責初始化視圖分發器,這部分稍微複雜一點。具體的步驟如下:
app->view_dispatcher = view_dispatcher_alloc();
view_dispatcher_enable_queue(app->view_dispatcher);
app->menu = menu_alloc();
app->popup = popup_alloc();
// 設置回調函式,將事件從視圖傳遞到場景管理器
view_dispatcher_set_event_callback_context(app->view_dispatcher, app);
view_dispatcher_set_custom_event_callback(
    app->view_dispatcher,
    test_app_scene_manager_custom_event_callback);
view_dispatcher_set_navigation_event_callback(
    app->view_dispatcher,
    test_app_scene_manager_navigation_event_callback);
// 將視圖添加到分發器,並根據它們的列舉值進行索引
view_dispatcher_add_view(
    app->view_dispatcher,
    TestAppView_Menu,
    menu_get_view(app->menu));
view_dispatcher_add_view(
    app->view_dispatcher,
    TestAppView_Popup,
    popup_get_view(app->popup));
今天就先到這邊,預計明天走完教學,後天做出自已的 app。
各位明天見!